package systole.view.accordion;

//Import the GUI classes
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

//Import the Java classes
import java.util.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import systole.view.tabs.JpnlAnalysis;

/**
 * A JOutlookBar provides a component that is similar to a JTabbedPane, but
 * instead of maintaining tabs, it uses Outlook-style bars to control the
 * visible component
 */
public class JAccordion extends JPanel implements ActionListener {

    /**
	 * 
	 */
	private static final long serialVersionUID = 2135064978928650236L;

	/**
     *  Kind of menu items to create
     */
    public enum Accordion { PATIENT, SIGNAL, SEGMENTS, FINAL_SEGMENT, REPORT };
    /**
     * The top panel: contains the buttons displayed on the top of the
     * JOutlookBar
     */
    private JPanel topPanel = new JPanel(new GridLayout(1, 1));
    /**
     * The bottom panel: contains the buttons displayed on the bottom of the
     * JOutlookBar
     */
    private JPanel bottomPanel = new JPanel(new GridLayout(1, 1));
    /**
     * A LinkedHashMap of bars: we use a linked hash map to preserve the order
     * of the bars
     */
    private Map<String, BarInfo> bars = new LinkedHashMap<String, BarInfo>();
    /**
     * The currently visible bar (zero-based index)
     */
    private int visibleBar = 0;
    /**
     * A place-holder for the currently visible component
     */
    private JComponent visibleComponent = null;
    private JpnlAnalysis analysis;

    /**
     * Creates a new JOutlookBar; after which you should make repeated calls to
     * addBar() for each bar
     *
     * @param analysis
     */
    public JAccordion(JpnlAnalysis analysis) {
        this.setLayout(new BorderLayout());
        this.setBorder(new CompoundBorder(new BevelBorder(BevelBorder.LOWERED), new BevelBorder(BevelBorder.RAISED)));
        this.add(topPanel, BorderLayout.NORTH);
        this.add(bottomPanel, BorderLayout.SOUTH);
        this.analysis = analysis;
    }

    /**
     * Adds the specified component to the JOutlookBar and sets the bar's name
     *
     * @param name
     *            The name of the outlook bar
     * @param kind
     * @param component
     * @param icon 
     */
    public void addBar(String name, Accordion kind, JComponent component, String icon) {
        BarInfo barInfo = new BarInfo(name, kind, component, icon);
        barInfo.getButton().addActionListener(this);
        this.bars.put(name, barInfo);
        render();
    }

    /**
     * Adds the specified component to the JOutlookBar and sets the bar's name
     *
     * @param name
     *            The name of the outlook bar
     * @param kind
     * @param icon
     *            An icon to display in the outlook bar
     * @param component
     */
    public void addBar(String name, Accordion kind, Icon icon, JComponent component) {
        BarInfo barInfo = new BarInfo(name, kind, icon, component);
        barInfo.getButton().addActionListener(this);
        this.bars.put(name, barInfo);
        render();
    }

    /**
     * Removes the specified bar from the JOutlookBar
     *
     * @param name
     *            The name of the bar to remove
     */
    public void removeBar(String name) {
        this.bars.remove(name);
        render();
    }

    /**
     * Returns the index of the currently visible bar (zero-based)
     *
     * @return The index of the currently visible bar
     */
    public int getVisibleBar() {
        return this.visibleBar;
    }

    /**
     * Programmatically sets the currently visible bar; the visible bar index
     * must be in the range of 0 to size() - 1
     *
     * @param visibleBar
     *            The zero-based index of the component to make visible
     */
    public void setVisibleBar(int visibleBar) {
        if (visibleBar > 0 && visibleBar < this.bars.size() - 1) {
            this.visibleBar = visibleBar;
            render();
        }
    }

    /**
     * Causes the outlook bar component to rebuild itself; this means that it
     * rebuilds the top and bottom panels of bars as well as making the
     * currently selected bar's panel visible
     */
    public void render() {
        // Compute how many bars we are going to have where
        int totalBars = this.bars.size();
        int topBars = this.visibleBar + 1;
        int bottomBars = totalBars - topBars;

        // Get an iterator to walk through out bars with
        Iterator<String> itr = this.bars.keySet().iterator();

        // Render the top bars: remove all components, reset the GridLayout to
        // hold to correct number of bars, add the bars, and "validate" it to
        // cause it to re-layout its components
        this.topPanel.removeAll();
        GridLayout topLayout = (GridLayout) this.topPanel.getLayout();
        topLayout.setRows(topBars);
        BarInfo barInfo = null;
        for (int i = 0; i < topBars; i++) {
            String barName = itr.next();
            barInfo = this.bars.get(barName);
            this.topPanel.add(barInfo.getButton());
        }
        this.topPanel.validate();

        // Render the center component: remove the current component (if there
        // is one) and then put the visible component in the center of this
        // panel
        if (this.visibleComponent != null) {
            this.remove(this.visibleComponent);
        }
        this.visibleComponent = barInfo.getComponent();
        this.add(visibleComponent, BorderLayout.CENTER);

        // Render the bottom bars: remove all components, reset the GridLayout
        // to hold to correct number of bars, add the bars, and "validate" it to
        // cause it to re-layout its components
        this.bottomPanel.removeAll();
        GridLayout bottomLayout = (GridLayout) this.bottomPanel.getLayout();
        bottomLayout.setRows(bottomBars);
        for (int i = 0; i < bottomBars; i++) {
            String barName = itr.next();
            barInfo = this.bars.get(barName);
            this.bottomPanel.add(barInfo.getButton());
        }
        this.bottomPanel.validate();

        // Validate all of our components: cause this container to re-layout its
        // subcomponents
        validate();
    }

    /**
     * Invoked when one of our bars is selected
     *
     * @param e
     */
    public void actionPerformed(ActionEvent e) {
        int currentBar = 0;
        for (Iterator<String> i = this.bars.keySet().iterator(); i.hasNext();) {
            String barName = i.next();
            BarInfo barInfo = this.bars.get(barName);
            if (barInfo.getButton() == e.getSource()) {
                // Found the selected button
                this.visibleBar = currentBar;
                render();
                this.analysis.showPnl(barInfo.kind);
                return;
            }
            currentBar++;
        }
    }

    /**
     * Internal class that maintains information about individual Outlook bars;
     * specifically it maintains the following information:
     *
     * name The name of the bar button The associated JButton for the bar
     * component The component maintained in the Outlook bar
     */
    class BarInfo {

        /**
         * The name of this bar
         */
        private String name;
        /**
         * The JButton that implements the Outlook bar itself
         */
        private JButton button;
        /**
         * The component that is the body of the Outlook bar
         */
        private JComponent component;
        private Accordion kind;

        /**
         * Creates a new BarInfo
         *
         * @param name
         *            The name of the bar
         * @param kind 
         * @param component
         *            The component that is the body of the Outlook Bar
         * @param icon 
         */
        public BarInfo(String name, Accordion kind, JComponent component,String icon) {
            this.name = name;
            this.component = component;
            //this.button = new JButton(name);
            this.button = new OvalButton(name,icon);
            this.kind = kind;
        }

        /**
         * Creates a new BarInfo
         *
         * @param name
         *            The name of the bar
         * @param kind 
         * @param icon
         *            JButton icon
         * @param component
         *            The component that is the body of the Outlook Bar
         */
        public BarInfo(String name, Accordion kind, Icon icon, JComponent component) {
            this.name = name;
            this.component = component;
            this.button = new JButton(name, icon);
            this.kind = kind;
        }

        /**
         * Returns the name of the bar
         *
         * @return The name of the bar
         */
        public String getName() {
            return this.name;
        }

        /**
         * Sets the name of the bar
         *
         * @param name of the bar
         */
        public void setName(String name) {
            this.name = name;
        }

        /**
         * Returns the outlook bar JButton implementation
         *
         * @return The Outlook Bar JButton implementation
         */
        public JButton getButton() {
            return this.button;
        }

        /**
         * Returns the component that implements the body of this Outlook Bar
         *
         * @return The component that implements the body of this Outlook Bar
         */
        public JComponent getComponent() {
            return this.component;
        }
    }
}
